import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpException } from '@nestjs/common'
import { Observable, throwError } from 'rxjs'
import { tap, catchError } from 'rxjs/operators'
import { Request, Response } from 'express'
import { LoggerService } from './logger.service'

/**
 * 日志拦截器
 * 自动记录控制器方法的执行情况
 */
@Injectable()
export class LoggerInterceptor implements NestInterceptor {
  constructor(private readonly logger: LoggerService) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const startTime = Date.now()
    const ctx = context.switchToHttp()
    const request = ctx.getRequest<Request>()
    const response = ctx.getResponse<Response>()

    const { method, originalUrl, ip, headers } = request
    const userAgent = headers['user-agent'] || ''
    const requestId = headers['x-request-id'] as string

    // 获取控制器和方法名
    const controllerName = context.getClass().name
    const methodName = context.getHandler().name

    // 获取用户信息（如果已认证）
    const user = (request as any).user
    const userId = user?.id

    const logContext = {
      requestId,
      ip,
      userAgent,
      method,
      url: originalUrl,
      controller: controllerName,
      handler: methodName,
      userId
    }

    // 记录请求开始
    this.logger.debug(`Controller method started: ${controllerName}.${methodName}`, logContext)

    return next.handle().pipe(
      tap(data => {
        const responseTime = Date.now() - startTime
        const statusCode = response.statusCode

        // 记录成功响应
        this.logger.debug(
          `Controller method completed: ${controllerName}.${methodName} - ${statusCode} (${responseTime}ms)`,
          {
            ...logContext,
            statusCode,
            responseTime,
            responseSize: JSON.stringify(data).length
          }
        )

        // 记录性能日志（如果响应时间过长）
        const performanceThreshold = 1000 // 1秒
        if (responseTime > performanceThreshold) {
          this.logger.logPerformance(`${controllerName}.${methodName}`, responseTime, performanceThreshold, logContext)
        }
      }),
      catchError(error => {
        const responseTime = Date.now() - startTime
        const statusCode = error instanceof HttpException ? error.getStatus() : 500

        // 记录错误响应
        this.logger.error(
          `Controller method failed: ${controllerName}.${methodName} - ${statusCode} (${responseTime}ms)`,
          error,
          {
            ...logContext,
            statusCode,
            responseTime,
            errorName: error.name,
            errorMessage: error.message
          }
        )

        return throwError(() => error)
      })
    )
  }
}

/**
 * 数据库操作日志拦截器
 * 专门用于记录数据库相关操作
 */
@Injectable()
export class DatabaseLoggerInterceptor implements NestInterceptor {
  constructor(private readonly logger: LoggerService) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const startTime = Date.now()
    const controllerName = context.getClass().name
    const methodName = context.getHandler().name

    // 判断是否为数据库操作方法
    const isDatabaseOperation = this.isDatabaseMethod(methodName)

    if (!isDatabaseOperation) {
      return next.handle()
    }

    const ctx = context.switchToHttp()
    const request = ctx.getRequest<Request>()
    const user = (request as any).user

    const logContext = {
      requestId: request.headers['x-request-id'] as string,
      userId: user?.id,
      controller: controllerName,
      method: methodName
    }

    return next.handle().pipe(
      tap(() => {
        const duration = Date.now() - startTime
        const tableName = this.extractTableName(controllerName, methodName)
        const operation = this.extractOperation(methodName)

        this.logger.logDatabase(operation, tableName, duration, logContext)
      }),
      catchError(error => {
        const duration = Date.now() - startTime
        const tableName = this.extractTableName(controllerName, methodName)
        const operation = this.extractOperation(methodName)

        this.logger.error(`Database operation failed: ${operation} on ${tableName} (${duration}ms)`, error, logContext)

        return throwError(() => error)
      })
    )
  }

  /**
   * 判断是否为数据库操作方法
   */
  private isDatabaseMethod(methodName: string): boolean {
    const databaseMethods = [
      'create',
      'save',
      'update',
      'delete',
      'remove',
      'find',
      'findOne',
      'findAll',
      'findBy',
      'get',
      'list',
      'search',
      'count',
      'insert',
      'upsert',
      'bulk'
    ]

    return databaseMethods.some(method => methodName.toLowerCase().includes(method.toLowerCase()))
  }

  /**
   * 从控制器名和方法名提取表名
   */
  private extractTableName(controllerName: string, methodName: string): string {
    // 移除Controller后缀
    let tableName = controllerName.replace(/Controller$/, '')

    // 转换为小写并添加复数形式
    tableName = tableName.toLowerCase()
    if (!tableName.endsWith('s')) {
      tableName += 's'
    }

    return tableName
  }

  /**
   * 从方法名提取操作类型
   */
  private extractOperation(methodName: string): string {
    const method = methodName.toLowerCase()

    if (method.includes('create') || method.includes('save') || method.includes('insert')) {
      return 'CREATE'
    }
    if (method.includes('update') || method.includes('upsert')) {
      return 'UPDATE'
    }
    if (method.includes('delete') || method.includes('remove')) {
      return 'DELETE'
    }
    if (method.includes('find') || method.includes('get') || method.includes('list') || method.includes('search')) {
      return 'SELECT'
    }

    return 'UNKNOWN'
  }
}
